package org.example.hrpc.rpc.core.impl;

import io.netty.channel.Channel;
import org.example.hrpc.common.URL;
import org.example.hrpc.common.constant.CommonConstant;
import org.example.hrpc.common.exception.RemotingException;
import org.example.hrpc.common.exception.RpcException;
import org.example.hrpc.common.spi.loader.ExtensionLoader;
import org.example.hrpc.config.RegistryConfig;
import org.example.hrpc.registry.Registry;
import org.example.hrpc.registry.RegistryFactory;
import org.example.hrpc.registry.RegistryService;
import org.example.hrpc.registry.zookeeper.ZookeeperRegistryFactory;
import org.example.hrpc.rpc.core.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RegistryProtocol implements Protocol {
    private static final Logger logger = LoggerFactory.getLogger(RegistryProtocol.class);
    private static final int DEFAULT_PORT = 9090;

    protected Protocol protocol;
    protected RegistryFactory registryFactory;
    protected ProxyFactory proxyFactory;

    public RegistryProtocol() {
        protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("hrpc");
        proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension("jdk");
    }

    @Override
    public int getDefaultPort() {
        return DEFAULT_PORT;
    }

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        // 后面的host参数和port参数是注册中心的地址
        // registry://host:port/path?version=1.0&register=true&host=127.0.0.1&port=2181
        // getRegistryUrl得到注册中心的地址
        final URL registryUrl = getRegistryUrl(invoker);

        boolean register = Boolean.parseBoolean(registryUrl.getParameter("register"));
        logger.info("registryurl: {} need to register to registry: {}", registryUrl, register);
        if(register) {
            if(registryFactory == null) {
                registryFactory = new ZookeeperRegistryFactory();
            }
            final URL providerUrl = getProviderUrl(invoker);
            final Registry registry = registryFactory.getRegistry(registryUrl);
            registry.register(providerUrl);
        }

        final Exporter<T> exporter = protocol.export(invoker);
        return exporter;
    }


    @Override
    public <T> Invoker<T> refer(Class<T> type, URL registryUrl) throws RpcException {
        if(registryFactory == null) {
            registryFactory = new ZookeeperRegistryFactory();
        }
        /**
         * 这里需要加入是否注册到register的逻辑
         */
        boolean register = Boolean.parseBoolean(registryUrl.getParameter("register"));
        if(register) {
            Registry registry = registryFactory.getRegistry(registryUrl);
            // 这里不太对，
            if(RegistryService.class.equals(type)) {
                return proxyFactory.getInvoker((T)registry, type, registryUrl);
            }

            return doRefer(registry, type, registryUrl);
        } else {
            return protocol.refer(type, registryUrl);
        }

    }

    @Override
    public Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException {
        return null;
    }

    @Override
    public void destroy() {

    }

    protected URL getRegistryUrl(Invoker<?> originInvoker) {
        URL url = originInvoker.getUrl();
        String host = url.getParameter("host");
        host = host == null ? "" : host;
        String port = url.getParameter("port");
        port = port == null ? "0" : port;
        return new URL(url.getProtocol(), host, Integer.parseInt(port), url.getPath(), url.getParameters());
    }

    protected URL getProviderUrl(Invoker<?> originInvoker) {
        return originInvoker.getUrl();
    }

    private <T> Invoker<T> doRefer(Registry registry, Class<T> type, URL url) {
        // 这里是不是要先根据url选择一个合适的服务提供者 向注册中心先调用相关请求
        URL providerURL = registry.discovery(url);
        logger.info("success get provider URL: {}", providerURL);
        Invoker<T> invoker = protocol.refer(type, providerURL);
        return invoker;
    }


    public Protocol getProtocol() {
        return protocol;
    }

    public void setProtocol(Protocol protocol) {
        this.protocol = protocol;
    }

    public RegistryFactory getRegistryFactory() {
        return registryFactory;
    }

    public void setRegistryFactory(RegistryFactory registryFactory) {
        this.registryFactory = registryFactory;
    }

    public ProxyFactory getProxyFactory() {
        return proxyFactory;
    }

    public void setProxyFactory(ProxyFactory proxyFactory) {
        this.proxyFactory = proxyFactory;
    }
}
